/*
 * Copyright 2006-2008 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package net.martinimix.service.syndication;

import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.SocketException;

import net.martinimix.domain.syndication.SyndicationFeed;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;

import com.sun.syndication.io.FeedException;

/**
 * Provides a file transfer protocol (FTP) feed publishing service.
 * 
 * <p>
 * This service defaults to using passive FTP connections.
 * </p>
 * 
 * @author Scott Rossillo
 *
 */
public class FTPFeedPublishingService extends AbstractRomeFeedPublishingService 
		implements SyndicationFeedPublishingService {

	private final static Log log = LogFactory.getLog(FTPFeedPublishingService.class);
	
	private String directory;
	private String host;
	private int port;
	private String username;
	private String password;
	
	private String feedBaseUrl;
	
	
	/**
	 * Creates a new FTP feed publishing service.
	 *  
	 */
	public FTPFeedPublishingService() {
	
		port = FTPClient.DEFAULT_PORT;
	}
	
	private String createUrl(String fileName) {
		
		StringBuffer url = new StringBuffer(1024);
		
		url.append(this.getFeedBaseUrl());
		if(!this.getFeedBaseUrl().endsWith("/")) {
			url.append('/');
		}
		url.append(fileName);
		
		return url.toString();
	}
	
	public String publishInternal(SyndicationFeed feed) throws SyndicationFeedPublishFailedException{
		
		FTPClient ftp = new FTPClient();
		OutputStream out;
		int reply;
		String remoteFileName = feed.getUrn() + ".xml";
		
		log.info("FTP publish requested of feed [" + feed.getId() + "]");
		
		try {
			ftp.connect(host, port);
			reply = ftp.getReplyCode();
			if(!FTPReply.isPositiveCompletion(reply)) {
				throw new SyndicationFeedPublishFailedException("FTP server [" + host + "] refused connection.");
			}
			
			ftp.login(username, password);
			reply = ftp.getReplyCode();
			if(!FTPReply.isPositiveCompletion(reply)) {
				throw new SyndicationFeedPublishFailedException("FTP server [" + host + "] refused login credentials.");
			}
			
			log.debug("Entering passive mode");
			ftp.enterLocalPassiveMode();
			
			if(directory !=null) {
				log.debug("Changing remote path to [" + directory + "]");
				ftp.changeWorkingDirectory(directory);
			}
			
			log.debug("Requesting to write file [" + remoteFileName + "]");
			out = ftp.storeFileStream(remoteFileName);			
			super.outputXML(feed, new OutputStreamWriter(out));
			log.debug("Wrote file");
			
			out.flush();
			out.close();
			
		} catch (SocketException e) {
			throw new SyndicationFeedPublishFailedException("Unable to create FTP connection to host [" + host + "]", e);
		} catch (IOException e) {
			throw new SyndicationFeedPublishFailedException("Unable to communicate with host [" + host + "]", e);
		} catch (FeedException e) {
			throw new SyndicationFeedPublishFailedException("Error generating feed: " + e.getMessage(), e);
		} finally {
			if(ftp.isConnected()) {
				try {
					ftp.disconnect();
				} catch (IOException e) {
					/* oh well */
				}
			}
		}
		
		return this.createUrl(remoteFileName);
	}

	public String getDirectory() {
		return directory;
	}

	public void setDirectory(String directory) {
		this.directory = directory;
	}

	public String getFeedBaseUrl() {
		return feedBaseUrl;
	}

	/**
	 * Sets the feed base URL for this publishing service.
	 * 
	 * @param feedBaseUrl
	 */
	public void setFeedBaseUrl(String feedBaseUrl) {
		this.feedBaseUrl = feedBaseUrl; 
	}

	public String getHost() {
		return host;
	}

	public void setHost(String host) {
		this.host = host;
	}

	public int getPort() {
		return port;
	}

	public void setPort(int port) {
		this.port = port;
	}

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

}
